package 笔试.面试手撕;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author:谢君臣
 * @Date:2021/9/6-16:11
 * @version:1.0
 * @function:
 */
public class 数据库连接池 {
    public static void main(String[] args) {
        pool pool = new pool(5);
        for (int i = 0; i < 15; i++) {
            String name = String.valueOf(i);
            new Thread(() -> {
                Connection connection = pool.getConnection();
                try {
                    TimeUnit.SECONDS.sleep(2);
                    pool.backFree(connection);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, name).start();
        }
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

class pool {
    private ReentrantLock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private volatile AtomicInteger size;
    //1. capacity
    private int capacity;
    //2. 定义链接数组
    private Connection[] connections;
    //3. 链接状态数组
    private AtomicIntegerArray state;

    //4. 初始化
    public pool(int capacity) {
        this.size = new AtomicInteger(0);
        this.capacity = capacity;
        this.connections = new Connection[capacity];
        this.state = new AtomicIntegerArray(new int[capacity]);
    }

    //5. 获取链接
    public Connection getConnection() {
        while (true) {
            lock.lock();
            try {
                int s = size.get();
                if (s < capacity && state.compareAndSet(s, 0, 1)) {//当前没有或者小于最大容量创建链接
                    Connection connection = new Connection();
                    connections[s] = connection;
                    size.incrementAndGet();
                    System.out.println(Thread.currentThread().getName()+"获得链接");
                    return connection;
                }
                for (int i = 0; i < capacity; i++) {
                    if (state.get(i) == 0 && state.compareAndSet(i, 0, 1)){
                        System.out.println(Thread.currentThread().getName()+"获得链接");
                        return connections[i];
                    }
                }
                // 最终还没拿到，则线程等待
                System.out.println(Thread.currentThread().getName() + "持续等待被唤醒");
                // 持续等待被唤醒
                conditionA.await();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    //6. 回收链接
    public void backFree(Connection connection) {
        lock.lock();
        try {
            for (int i = 0; i < capacity; i++) {
                if (connection == connections[i]) {
                    state.set(i, 0);
                    break;
                }
            }
            System.out.println(Thread.currentThread().getName() + "归还链接，唤醒等待线程");
            conditionA.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

class Connection {
}